<?php
$settings = variable_get ('paypal_settings', array ());

$has_txn_key = false;
$i = array();
$debug = "PayPal IPN Results\n";
$debug .= "==================\n";

/* Read the post from PayPal system and add 'cmd' */
$req = 'cmd=_notify-validate';

ksort($_POST); //easier for debugging

foreach ($_POST as $key => $value) {
  $debug .= "$key = $value\n";

  if (strstr($key, 'item_number')) {
    if (strstr($value, 'txnid_')) {
      $txnid = substr($value, strlen('txnid_'));
      $has_txn_key = true;
      $debug .= t("A Transaction ID exists and is #%key\n", array('%key' => $txnid));
    }

    $i[substr($key, strlen('item_number'))] = $txnid;
  }
  elseif (strstr($key, 'quantity')) {
    $quantity[substr($key, strlen('quantity'))] = $value;
  }
  elseif (strstr($key, 'item_name')) {
    $name[substr($key, strlen('item_name'))] = $value;
  }

  $value = urlencode(stripslashes($value));
  $req .= "&$key=$value";
}

if ($txnid) {
  watchdog('paypal', t('IPN hit for <a href="%txn-url">txn: %txnid</a>', array('%txnid' => theme('placeholder', $txnid), '%txn-url' => url('admin/store/search&txnid='. $txnid))));
}
else {
  watchdog('paypal', t('IPN hit, no transaction ID given.'));
}

foreach ($i as $key => $value) {
  $pp_item = new StdClass();
  $pp_item->nid = $value;
  $pp_item->qty = $quantity[$key];
  $pp_item->title = $name[$key];
  $pp_item->price = null;
  $item[] = $pp_item;
}

/* Post back to PayPal system to validate */
$ipnrb = parse_url($settings['ipnrb_url']);

if ($ipnrb['scheme']=='http') {
  $port = 80;
  $host = $ipnrb['host'];
}
else {
  $port = 443;
  $host = "ssl://{$ipnrb['host']}";
}

$header = "POST {$ipnrb['path']} HTTP/1.0\r\n";
$header .= "Host: {$ipnrb['host']}:$port\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
$fp = fsockopen($host, $port, $errno, $errstr, 30);

/* Assign posted variables to local variables */
$payment_status = $_POST['payment_status'];
$fee            = $_POST['payment_fee'];
$payment_amount = $_POST['mc_gross'];
$ppid           = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];

// HTTP ERROR
if (!$fp) {
  $debug .= t("An HTTP error occurred\n");
}
// We can't do much without a txn_id
elseif ($ppid && $has_txn_key) {
  fputs ($fp, $header . $req);
  while (!feof($fp)) {
    $res = fgets ($fp, 1024);
    if (strcmp ($res, 'VERIFIED') == 0 && $receiver_email == $settings['paypal_receiver_email']) {
      $debug .= t("PayPal has verified the transaction\n");
      
      $data['gross']          = $payment_amount;
      $data['fee']            = $fee;
      $data['payment_method'] = 'paypal';
      $data['payment_status'] = payment_get_status_id($payment_status);
      $data['ppid']           = $ppid;

      if ($has_txn_key) {
        $data['txnid'] = $txnid;
      }
      else {
        $data['billing_firstname']  = $_POST['address_first_name'];
        $data['billing_lastname']   = $_POST['address_last_name'];
        $data['billing_street1']    = $_POST['address_street'];
        $data['billing_city']       = $_POST['address_city'];
        $data['billing_state']      = $_POST['address_state'];
        $data['billing_zip']        = $_POST['address_zip'];
        $data['billing_country']    = store_get_country_id($_POST['address_country']);
        $data['items']              = $item;
        $data['uid']                = db_result(db_query("SELECT uid FROM {users} WHERE mail = '%s'", $_POST['payer_email']));
      }
      ksort($data);
      $debug .= "\nData being sent to store_transaction_save:\n===================================\n";
      foreach ($data as $key => $value) {
        $debug .= "$key = $value\n";
      }
      $debug .= "\n";

      $is_new = (db_result(db_query('SELECT COUNT(txnid) FROM {ec_paypal} WHERE ppid = %d', $ppid))) ? false : true;

      switch (strtoupper($payment_status)) {
        /* if referring to an initial purchase, this means the payment has
           been completed and the funds are successfully in your account
           balance. If referring to a reversal (i.e. txn_type= reversal ),
           then it means the reversal has been completed and funds have been
           removed from your account and returned to the customer */
        case 'COMPLETED':
            $data['payment_status'] = payment_get_status_id('completed');
            // If there are no shippable items, assume the transaction workflow is complete.
            $has_shippable_item = FALSE;
            $txn = store_transaction_load($txnid);
            foreach ($txn->items as $item) {
              if (product_is_shippable($item->vid)) {
                $has_shippable_item = TRUE;
              }
            }
            if (!$has_shippable_item) {
              $data['workflow'] = 6;
            }
            $txnid = store_transaction_save($data);
            if ($is_new && $txnid) {
              /* Compose and send confirmation email to the user */
              store_send_invoice_email($txnid);
            }
          break;

        /* The payment is pending; the pending_reason variable will give you
           more information. Note: You will receive another Instant Payment
           Notification when the payment becomes "Completed", "Failed", or "Denied" */
        case 'PENDING':
          $data['payment_status'] = payment_get_status_id('pending');
          $txnid = store_transaction_save($data);
          break;

        /* The payment has failed. This will only happen if the payment was
           made from your customer's bank account */
        case 'FAILED':
          $data['payment_status'] = payment_get_status_id('failed');
          $txnid = store_transaction_save($data);
          break;

        /* You, the merchant, denied the payment. This will only happen if the
           payment was previously pending due to one of the pending reasons below */
        case 'DENIED':
          $data['payment_status'] = payment_get_status_id('denied');
          $txnid = store_transaction_save($data);
          break;

        /* You, the merchant, refunded the payment. */
        case 'REFUNDED':
          $data['payment_status'] = payment_get_status_id('refunded');
          $txnid = store_transaction_save($data);
          break;

        /* This means a reversal has been canceled (e.g. you, the merchant,
           won a dispute with the customer and the funds for the transaction
           that was reversed have been returned to you) */
        case 'CANCELED':
          $data['payment_status'] = payment_get_status_id('canceled');
          $txnid = store_transaction_save($data);
          break;

        default:
          /* Unkmown payment status */
      }
      $debug .= t("Transaction has been processed.\n");

    }
    else if (strcmp ($res, 'INVALID') == 0) {
      /* log for manual investigation */
      $debug .= t("The transaction has returned an invalid result from PayPal.\n");
    }
  }
}

fclose ($fp);

if ($settings['debug']) {
  // $filename = 'pp.txt';
  // $handle = fopen($filename, 'a');
  // fwrite($handle, $debug);
  // close($handle);

  $from       = variable_get ('site_mail', '');
  $to         = $from;
  $subject    = t('PayPal debug results for'). ' '. variable_get ('site_name', 'Drupal');
  $body       = $debug;
  
  drupal_mail('ec_paypal_debug', $to, $subject, $body, NULL, array (
    'From' => $from,
    'Reply-to' => $from,
    'X-Mailer' => 'Drupal',
    'Return-path' => $from,
    'Errors-to' => $from
  ));
}

